package com.sky.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.exception.BadArgsException;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.result.Result;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.BusinessDataVO;
import com.sky.vo.OrderReportVO;
import com.sky.vo.SalesTop10ReportVO;
import com.sky.vo.TurnoverReportVO;
import com.sky.vo.UserReportVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.FileCopyUtils;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author ghy
 * @version 1.0.1
 * @date 2023-05-03 10:41:23
 */
@Service
@Slf4j
public class ReportServiceImpl implements ReportService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private UserMapper userMapper;

    /**
     *
     * @param begin   2023-04-02
     * @param end     2023-05-01
     * @return
     */
    @Override
    public Result<TurnoverReportVO> turnoverStatistics(LocalDate begin, LocalDate end) {
        // 一.校验参数
        if(begin == null || end == null) {
            throw new BadArgsException("开始时间和结束时间必须都不为空！！");
        }

        // 二.处理业务
        // 1.获取时间范围内的每一天，变成字符串
        List<LocalDate> dateList = getDateList(begin, end);
        //2.获取每一天的营业额
        List<BigDecimal> turnoverList = new ArrayList<>();
        /*dateList.stream().forEach(item -> {
            // select sum(amount) from orders where status = 5 and order_time > 2023-04-02 00:00:00 and order_time < 2023-04-02 23:59:59
            //当天最小的时间
            LocalDateTime minTime = LocalDateTime.of(item, LocalTime.MIN);
            LocalDateTime maxTime = LocalDateTime.of(item, LocalTime.MAX);
            BigDecimal turnover = orderMapper.getDayTurnover(5, minTime, maxTime);
            turnover = turnover == null ? new BigDecimal(0) : turnover;
            turnoverList.add(turnover);
        });*/

        dateList.forEach(item -> {
            // select sum(amount) from orders where status = 5 and order_time > 2023-04-02 00:00:00 and order_time < 2023-04-02 23:59:59
            //当天最小的时间
            LocalDateTime minTime = LocalDateTime.of(item, LocalTime.MIN);
            LocalDateTime maxTime = LocalDateTime.of(item, LocalTime.MAX);
            BigDecimal turnover = orderMapper.getDayTurnover(minTime, maxTime, Orders.COMPLETED);
            turnover = turnover == null ? new BigDecimal(0) : turnover;
            turnoverList.add(turnover);
        });

        // 三.封装数据
        // dateList    //2022-10-01,2022-10-02,2022-10-03
        // turnoverList
        TurnoverReportVO turnoverReportVO = TurnoverReportVO.builder()
                //把集合中的元素以，的方式进行连接，变成一个字符串
                .dateList(StringUtils.join(dateList, ","))
                .turnoverList(StringUtils.join(turnoverList, ","))
                .build();
        return Result.success(turnoverReportVO);
    }

    @Override
    public Result<UserReportVO> userStatistics(LocalDate begin, LocalDate end) {
        // 一.校验参数
        if(begin == null || end == null) {
            throw new BadArgsException("开始时间和结束时间必须都不为空！！");
        }

        // 二.处理业务
        // 1.获取时间范围内的每一天，变成字符串
        List<LocalDate> dateList = getDateList(begin, end);
        List<Long> newUserList = new ArrayList<>(dateList.size());
        List<Long> totalUserList = new ArrayList<>(dateList.size());
        dateList.forEach(item -> {
            LocalDateTime minTime = LocalDateTime.of(item, LocalTime.MIN);
            LocalDateTime maxTime = LocalDateTime.of(item, LocalTime.MAX);
            // 2.获取每天的新用户量 select count(1) from user where create_time > 2023-04-25 00:00:00 and create_time < 2023-04-25 23:59:59
            Long newUser = userMapper.getUserCount(minTime, maxTime);
            // 3.获取总用户量 select count(1) from user where create_time < 2023-04-25 23:59:59
            Long totalUser = userMapper.getUserCount(null, maxTime);
            newUserList.add(newUser);
            totalUserList.add(totalUser);
        });

        // 三.封装数据
        UserReportVO userReportVO = UserReportVO.builder()
                .dateList(StringUtils.join(dateList, ","))
                .newUserList(StringUtils.join(newUserList, ","))
                .totalUserList(StringUtils.join(totalUserList, ","))
                .build();
        return Result.success(userReportVO);
    }

    @Override
    public Result<OrderReportVO> ordersStatistics(LocalDate begin, LocalDate end) {
        // 一.校验参数
        if(begin == null || end == null) {
            throw new BadArgsException("开始时间和结束时间必须都不为空！！");
        }

        // 二.处理业务
        // 1.获取时间范围内的每一天，变成字符串
        List<LocalDate> dateList = getDateList(begin, end);
        List<Long> orderCountList = new ArrayList<>(dateList.size());
        List<Long> validOrderCountList = new ArrayList<>(dateList.size());
        dateList.forEach(item -> {
            LocalDateTime minTime = LocalDateTime.of(item, LocalTime.MIN);
            LocalDateTime maxTime = LocalDateTime.of(item, LocalTime.MAX);
            // 2.获取每天的订单总数
            Long orderCount = orderMapper.getDayCount(minTime, maxTime, null);
            // 3.获取每天的有效订单总数
            Long validOrderCount = orderMapper.getDayCount(minTime, maxTime, Orders.COMPLETED);

            orderCountList.add(orderCount);
            validOrderCountList.add(validOrderCount);

        });
        Long totalOrderCount = orderCountList.stream().reduce(Long::sum).get();  //把集合中所有的元素进行累加
        Long validTotalOrderCount = validOrderCountList.stream().reduce(Long::sum).get();
        Double orderCompletionRate = 0.0;
        if(totalOrderCount != 0) {
            orderCompletionRate = validTotalOrderCount.doubleValue() / totalOrderCount;
        }

        OrderReportVO orderReportVO = OrderReportVO.builder()
                .dateList(StringUtils.join(dateList, ","))
                .orderCountList(StringUtils.join(orderCountList, ","))
                .validOrderCountList(StringUtils.join(validOrderCountList, ","))
                .totalOrderCount(totalOrderCount.intValue())
                .validOrderCount(validTotalOrderCount.intValue())
                .orderCompletionRate(orderCompletionRate)
                .build();
        return Result.success(orderReportVO);
    }

    @Override
    public Result<SalesTop10ReportVO> top10(LocalDate begin, LocalDate end) {
        // 一.校验参数
        if(begin == null || end == null) {
            throw new BadArgsException("开始时间和结束时间必须都不为空！！");
        }

        LocalDateTime minTime = LocalDateTime.of(begin, LocalTime.MIN);
        LocalDateTime maxTime = LocalDateTime.of(end, LocalTime.MAX);
        List<GoodsSalesDTO> goodsSalesDTOList = orderMapper.getSaleTop10(minTime, maxTime, Orders.COMPLETED);
        /**
         * AA  10
         * BB  23
         *
         * AA,BB
         * 10,23
         */
        /*List<String> nameList = goodsSalesDTOList.stream().map(item -> {
            return item.getName();
        }).collect(Collectors.toList());*/
        List<String> nameList = goodsSalesDTOList.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());
        List<Integer> numberList = goodsSalesDTOList.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());

        SalesTop10ReportVO salesTop10ReportVO = SalesTop10ReportVO.builder()
                .nameList(StringUtils.join(nameList, ","))
                .numberList(StringUtils.join(numberList, ","))
                .build();

        return Result.success(salesTop10ReportVO);
    }


    /**
     * 获取两个时间范围内的每一天，封装到一个集合中
     * @param begin
     * @param end
     * @return
     */
    private List<LocalDate> getDateList(LocalDate begin, LocalDate end) {
        List<LocalDate> dateList = new ArrayList<>();
        dateList.add(begin);  //第一天
        while (!begin.equals(end)) {
            begin = begin.plusDays(1);   //往后加一天
            dateList.add(begin);  //把后面的一天加到集合中
        }
        return dateList;
    }

    @Autowired
    private WorkspaceService workspaceService;

    @Override
    public void export(HttpServletResponse response) {
        try {
            //1.准备数据
            //2023-04-04 ~ 2023-05-03
            LocalDate now = LocalDate.now();
            LocalDate begin = now.minusDays(30);  //2023-04-04
            LocalDate end = now.minusDays(1);   //2023-05-03
            LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
            //近30天的总数据
            BusinessDataVO businessData = workspaceService.getBusinessData(beginTime, endTime);
            //近30天内每一天的数据
            List<BusinessDataVO> businessDataVOList = new ArrayList<>(30);
            for (int i = 0; i < 30; i++) {
                LocalDate date = begin.plusDays(i);  //每一天
                LocalDateTime beginTime1 = LocalDateTime.of(date, LocalTime.MIN);
                LocalDateTime endTime1 = LocalDateTime.of(date, LocalTime.MAX);
                BusinessDataVO businessData1 = workspaceService.getBusinessData(beginTime1, endTime1);
                businessData1.setDate(date.toString());
                businessDataVOList.add(businessData1);
            }
            //2.填充文件
            String templateFileName = this.getClass().getClassLoader().getResource("templates/运营数据报表模板.xlsx").getPath();
            log.warn("原模板文件名:{}", templateFileName);
            templateFileName = URLDecoder.decode(templateFileName, "UTF-8");
            log.warn("解码后模板文件名:{}", templateFileName);
            String fileName = this.getClass().getClassLoader().getResource("templates/temp.xlsx").getPath();
            //填充数据
            ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();
            FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
            excelWriter.fill(businessDataVOList, fillConfig, writeSheet);
            excelWriter.fill(businessData, writeSheet);
            excelWriter.close();
            //3.下载
            // 指定下载文件的 mine-type 类型
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 处理下载文件名的中文乱码
            String downloadFilename = URLEncoder.encode("运营数据报表模板", "UTF-8").replaceAll("\\+", "%20");
            // 告知浏览器以附件的形式去打开该资源
            // 原理：浏览器可以解析，则直接在浏览器中展示。浏览器不能解析，就下载
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + downloadFilename + ".xlsx");
            // 原始下载：把服务器上文件写到本地
            FileInputStream in = new FileInputStream(fileName);
            ServletOutputStream out = response.getOutputStream();
            FileCopyUtils.copy(in, out);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
